package com.sunk.fenbushishiwu.dtp.xa;

import com.mysql.cj.jdbc.JdbcConnection;
import com.mysql.cj.jdbc.MysqlXAConnection;
import com.mysql.cj.jdbc.MysqlXid;

import javax.sql.XAConnection;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TM {

    public void excute(Connection accountConn, Connection redConn) throws SQLException, XAException {
        //打印XA的事务日志 true代表打印
        boolean logXaCommands =true;
        //获取RM1的接口实例
        XAConnection xaConn1 = new MysqlXAConnection((JdbcConnection) accountConn,logXaCommands);
        XAResource rm1=xaConn1.getXAResource();

        //获取RM2的接口实例
        XAConnection xaConn2 = new MysqlXAConnection((JdbcConnection) redConn,logXaCommands);
        XAResource rm2=xaConn2.getXAResource();

        //生成全局ID gtrid：全局事务ID，不得超过64，建议使用十六进制数。
        byte[] globalid = "g12345".getBytes();
        //formatID：是一个无符号整数，用于标记gtrid和bqual值的格式，默认为1，长度不超过64.
        int formatId=1;
        //bqual：分支限定符(branch qualifier)，如果没有提供bqual，那么默认值为空字符串''，长度不超过64，建议使用十六进制数。
        //可以理解为全局事务中，A业务操作为分支一，B业务操作为分支二
        byte[] bqual1="b001".getBytes();
        //把rm1的事务分支id,注册到全局事务ID
        Xid xid1=new MysqlXid(globalid,bqual1,formatId);
        //TM 把rm2的事务分支id,注册到全局事务ID
        byte[] bqual2="b002".getBytes();
        Xid xid2=new MysqlXid(globalid,bqual2,formatId);
        try{

            rm1.start(xid1,XAResource.TMNOFLAGS);

            String sql="update capital_account set balance_amount = balance_amount-90 where user_id=1";
            PreparedStatement ps1 = accountConn.prepareStatement(sql);
            ps1.execute();
            rm1.end(xid1,XAResource.TMSUCCESS);

            rm2.start(xid2,XAResource.TMNOFLAGS);
            //模拟购物一个物品，用红包支付10元
            sql="update red_packet_account set balance_amount = balance_amount-10 where user_id=1";
            PreparedStatement ps2 = redConn.prepareStatement(sql);
            ps2.execute();
            rm2.end(xid2,XAResource.TMSUCCESS);
            // ===================两阶段提交================================
            // 第一阶段：询问所有的RM 准备提交事务分支
            int rm1_prepare=rm1.prepare(xid1);
            int rm2_prepare=rm2.prepare(xid2);
            //TM判断有2个事务分支，所以不能优化为一阶段提交
            boolean onePhase =false;
            // 第二阶段：真正提交
            if(rm1_prepare == XAResource.XA_OK && rm2_prepare == XAResource.XA_OK){
                rm1.commit(xid1,onePhase);
                rm2.commit(xid2,onePhase);
            }else{
                rm1.rollback(xid1);
                rm2.rollback(xid2);
            }
        } catch (XAException e) {
            //出现异常也回滚
            rm1.rollback(xid1);
            rm2.rollback(xid2);
            e.printStackTrace();
        }
    }
}

//        Tue Mar 03 13:50:08 CST 2020 DEBUG: Executing XA statement: XA START 0x673132333435,0x62303031,0x1
//        Tue Mar 03 13:50:08 CST 2020 DEBUG: Executing XA statement: XA END 0x673132333435,0x62303031,0x1
//        Tue Mar 03 13:50:08 CST 2020 DEBUG: Executing XA statement: XA START 0x673132333435,0x62303032,0x1
//        Tue Mar 03 13:50:08 CST 2020 DEBUG: Executing XA statement: XA END 0x673132333435,0x62303032,0x1
//        Tue Mar 03 13:50:08 CST 2020 DEBUG: Executing XA statement: XA PREPARE 0x673132333435,0x62303031,0x1
//        Tue Mar 03 13:50:08 CST 2020 DEBUG: Executing XA statement: XA PREPARE 0x673132333435,0x62303032,0x1
//        Tue Mar 03 13:50:08 CST 2020 DEBUG: Executing XA statement: XA COMMIT 0x673132333435,0x62303031,0x1
//        Tue Mar 03 13:50:08 CST 2020 DEBUG: Executing XA statement: XA COMMIT 0x673132333435,0x62303032,0x1
